package com.atguigu.spzx.common.log.aspect;

import com.atguigu.spzx.common.log.annotation.Log;
import com.atguigu.spzx.common.log.service.SysOperLogService;
import com.atguigu.spzx.common.log.utils.LogUtil;
import com.atguigu.spzx.model.entity.system.SysOperLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class LogAspect implements Ordered {


    @Autowired
    private SysOperLogService sysOperLogService;



    /**
     * 通知类型：
     *  @Around:环绕通知
     *
     *  参数部分：切点表达式
     *点表达式：
     * 方式一：可以通过直接配置全路径的方式
     *  @Around("@annotation( com.atguigu.spzx.common.log.annotation.Log)")
     *
     *  方式二：可以通过在参数列表中声明注解类型，表达式中配置指定注解类型的变量
     *   @Around("@annotation(syLog)")
     *
     * 区别：
     *    本质上没有区别，只是形式上不同
     *    第二种方式在操作过程中更加方便，可以直接获取被增强方法的独有数据
     *
     *   proceed = joinPoint.proceed();  执行被增强的方法
     * @return
     * @throws Throwable
     */
    @Around("@annotation(syLog)")
    public Object doAroundAdvice(ProceedingJoinPoint joinPoint ,Log syLog) throws Throwable {

        //创建日志对象
        SysOperLog sysOperLog=new SysOperLog();
        //方法执行之前收集的数据
        LogUtil.beforeHandleLog(syLog,joinPoint,sysOperLog);
        Object proceed = null;

        try {
            //执行目标方法
            proceed = joinPoint.proceed();

            //收集目标方法执行正确的结果
            LogUtil.afterHandlLog(syLog,proceed,sysOperLog,0,null);
        } catch (Throwable e) {
            //方法执行之后的异常信息收集
            LogUtil.afterHandlLog(syLog,proceed,sysOperLog,1,e.getMessage());
            //执行保存日志

            sysOperLogService.saveSysOperLog(sysOperLog);
            e.printStackTrace();
            //此时如果不抛出，事务处理接收不到异常，在处理时，不会回滚
            throw  new RuntimeException();
        }



        return proceed;
    }

    /**
     * 设置切面类的优先级
     * @return
     */
    @Override
    public int getOrder() {
        return -1000;
    }
}
